﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.Integration;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Xml;
using System.Threading;
using Ricciolo.StylesExplorer.Forms;
using System.Security.Permissions;
using System.Security;
using System.Runtime.Remoting;

namespace Ricciolo.StylesExplorer.Controls
{
    public partial class XamlPreview : UserControl
    {

        private AppDomain appDomain;
        private PreviewZone previewZone;
        private Thread previewThread;

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern IntPtr SetParent(HandleRef hWnd, HandleRef hWndParent);

        public XamlPreview()
        {
            InitializeComponent();

            if (System.ComponentModel.LicenseManager.UsageMode == LicenseUsageMode.Runtime)
                StartPreview();
        }

        /// <summary>
        /// Set xaml to preview
        /// </summary>
        /// <param name="xaml"></param>
        public void SetXaml(string xaml)
        {
            try
            {
                if (previewZone != null)
                    previewZone.SetXaml(xaml);
            }
            catch (RemotingException re)
            {
                Debug.WriteLine(re.ToString());
                StopPreview();
                StartPreview();
            }
        }

        /// <summary>
        /// Start preview zone in a new message loop
        /// </summary>
        public void StartPreview()
        {
            if (appDomain != null)
                AppDomain.Unload(appDomain);

            initializing.Visible = true;

            // Create control on other AppDomain
            AppDomainSetup setup = new AppDomainSetup();
            setup.ApplicationBase = Environment.CurrentDirectory;
            appDomain = AppDomain.CreateDomain(typeof(XamlPreview).Name, null, setup, new PermissionSet(PermissionState.Unrestricted));
            appDomain.DomainUnload += new EventHandler(appDomain_DomainUnload);
            appDomain.UnhandledException += new UnhandledExceptionEventHandler(appDomain_UnhandledException);

            HandleRef previewPanelRef = new HandleRef(previewPanel, previewPanel.Handle);

            // Start a new message loop on other thread
            previewThread = new Thread(delegate()
                {
                    previewZone = (PreviewZone)appDomain.CreateInstanceAndUnwrap(typeof(PreviewZone).Assembly.FullName, typeof(PreviewZone).FullName);
                    SetParent(new HandleRef(previewZone, previewZone.Handle), previewPanelRef);
                    previewZone.Location = new Point(0, 0);
                    previewZone.Size = previewPanel.ClientRectangle.Size;
                    previewZone.Start();
                });
            previewThread.SetApartmentState(ApartmentState.STA);
            previewThread.IsBackground = true;
            previewThread.Start();
        }

        void appDomain_DomainUnload(object sender, EventArgs e)
        {
            previewCheckBox.Checked = false;
        }

        void appDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Debug.WriteLine(e.ExceptionObject.ToString());
        }

        private void previewCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (previewCheckBox.Checked)
                StartPreview();
            else
                StopPreview();
        }

        private void StopPreview()
        {
            if (appDomain == null) return;

            initializing.Visible = false;

            try
            {
                // Unload all
                try
                {
                    previewZone.Stop();
                    AppDomain.Unload(appDomain);
                }
                finally
                {
                    appDomain = null;
                    previewZone = null;
                }
            }
            catch
            {
                Debug.WriteLine("Error while unloading preview AppDomain");
            }
        }

        private void previewPanel_Resize(object sender, EventArgs e)
        {
            if (previewZone != null)
                previewZone.Resize(previewPanel.ClientRectangle.Size);
        }
    }
}
